package br.com.caesarhoppen.compression;

import java.util.ArrayList;
import java.util.Hashtable;

public class Huffman01 {

	public static void main(String[] args) {

		// The following data structure is used to
		// communicate encoding particulars from the Huffman
		// encoder to the Huffman decoder. This is necessary
		// for the decoder to be able to decode the encoded
		// message. Note that this data structure must be
		// empty when it is passed to the encode method.
		Hashtable<Character, String> huffEncodeTable = null;

		// Begin the demonstration by applying Huffman encoding
		// to a text message.

		// Create and display the raw text message that will be
		// encoded. Display 48 characters to the line.

		// Modify the comment indicators to enable one of the
		// following test messages, or insert a test message
		// of your own and then recompile the program.
		/*
		 * //The following test message was copied directly from // an Internet
		 * news site. It is probably // representative of typical English text.
		 * String rawData = "BAGHDAD, Iraq Violence increased " +
		 * "across Iraq after a lull following the Dec. 15 " +
		 * "parliamentary elections, with at least two dozen " +
		 * "people including a U.S. soldier killed Monday in " +
		 * "shootings and bombings mostly targeting the Shiite-" +
		 * "dominated security services. The Defense Ministry " +
		 * "director of operations, Brig. Gen. Abdul Aziz " +
		 * "Mohammed-Jassim, blamed increased violence in the " +
		 * "past two days on insurgents trying to deepen the " +
		 * "political turmoil following the elections. The " +
		 * "violence came as three Iraqi opposition groups " +
		 * "threatened another wave of protests and civil " +
		 * "disobedience if allegations of fraud are not " +
		 * "properly investigated.";
		 */
		/*
		 * String rawData = "Now is the time for all good men " +
		 * "to come to the aid of their country.";
		 */

		double[] teste = new double[2];
		teste[0] = 1;
		teste[1] = 2;
//		String rawData = Arrays.toString(teste);
		// Use the following test message or some other
		// similarly short test message to illustrate the
		// construction of the HuffTree object.
		String rawData = "Esse era um texto que eu queria esteganografar.";

		// Enable the following two statements to display the
		// raw data 48 characters to the line.
		System.out.println("Raw Data");
		display48(rawData);

		int rawDataLen = rawData.length();

		System.out.println("nNumber raw data bits: " + rawData.length() * 8);

		// Instantiate a Huffman encoder object
		HuffmanEncoder encoder = new HuffmanEncoder();

		// Encode the raw text message. The encoded message
		// is received back as bytes stored in an ArrayList
		// object. Pass the raw message to the encode
		// method. Also pass a reference to the empty data
		// structure mentioned above to the encode method where
		// it will be populated with encoding particulars
		// needed to decode the message later
		huffEncodeTable = new Hashtable<Character, String>();
		ArrayList<Byte> binaryEncodedData = encoder.encode(rawData,	huffEncodeTable);

		System.out.println("Number binary encoded data bits: " + binaryEncodedData.size() * 8);
		System.out.println("Compression factor: " + (double) rawData.length() / binaryEncodedData.size());
		Byte b = binaryEncodedData.get(0);
		binaryEncodedData.set(0, new Byte((byte) (b & 0xEE)));

		// The message has now been Huffman encoded. Display the
		// binaryEncodedData in Hexadecimal format, 48
		// characters per line.
		System.out.println("Binary Encoded Data in Hexadecimal Format");
		hexDisplay48(binaryEncodedData);
		System.out.println();

		// Now continue the demonstration by decoding the
		// Huffman-encoded message.

		// Instantiate a Huffman decoder object.
		HuffmanDecoder decoder = new HuffmanDecoder();

		// Pass the encoded message to the decode method of the
		// HuffmanDecoder object. Also pass a reference
		// to the data structure containing encoding
		// particulars to the decode method. Also pass the
		// length of the original message so that extraneous
		// characters on the end of the decoded message can be
		// eliminated.
		String decodedData = decoder.decode(binaryEncodedData, huffEncodeTable, rawDataLen);

		// Display the decoded results, 48 characters to the
		// line
		System.out.println("nDecoded Data");
		display48(decodedData);

	}// end main

	// -----------------------------------------------------//
	// Utility method to display a String 48 characters to
	// the line.
	static void display48(String data) {
		for (int cnt = 0; cnt < data.length(); cnt += 48) {
			if ((cnt + 48) < data.length()) {
				// Display 48 characters.
				System.out.println(data.substring(cnt, cnt + 48));
			} else {
				// Display the final line, which may be short.
				System.out.println(data.substring(cnt));
			}// end else
		}// end for loop
	}// end display48

	// -----------------------------------------------------//

	// Utility method to display hex data 48 characters to
	// the line
	static void hexDisplay48(ArrayList<Byte> binaryEncodedData) {
		int charCnt = 0;
		for (Byte element : binaryEncodedData) {
			System.out.print(Integer.toHexString((int) element & 0X00FF));
			charCnt++;
			if (charCnt % 24 == 0) {
				System.out.println();// new line
				charCnt = 0;
			}// end if
		}// end for-each
	}// end hexDisplay48
	// -----------------------------------------------------//
}// end class Huffman01
// =======================================================//
